package com.waigoulin.infrastructure.adapter.port;

import com.google.common.cache.Cache;
import com.waigoulin.domain.auth.adapter.port.ILoginPort;
import com.waigoulin.infrastructure.gateway.IWeixinApiService;
import com.waigoulin.infrastructure.gateway.IpLocationApiService;
import com.waigoulin.infrastructure.gateway.dto.lbs.IpLocationResponseDTO;
import com.waigoulin.infrastructure.gateway.dto.weixin.WeixinQrCodeRequestDTO;
import com.waigoulin.infrastructure.gateway.dto.weixin.WeixinQrCodeResponseDTO;
import com.waigoulin.infrastructure.gateway.dto.weixin.WeixinTemplateMessageDTO;
import com.waigoulin.infrastructure.gateway.dto.weixin.WeixinTokenResponseDTO;
import com.waigoulin.types.common.Constants;
import com.waigoulin.types.sdk.lbs.IpLocationUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import retrofit2.Call;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;


/**
 * @FileName LoginPort
 * @Description 登录服务基础设施层接口实现类
 * @Author waigoulin
 * @date 2025-07-30
 **/
@Slf4j
@Service
public class LoginPort implements ILoginPort {

    @Value("${weixin.config.app-id}")
    private String appid; // 微信公众号id

    @Value("${weixin.config.app-secret}")
    private String appSecret; // 微信公众号密钥

    @Value("${weixin.config.template-id}")
    private String template_id; // 微信公众号模板信息模板id

    @Value("${weixin.config.access-token.expire-seconds}")
    private int access_token_expires_time;

    @Value("${weixin.config.ticket.expire-seconds}")
    private int ticket_expire_time; // 微信登录凭证过期时间

    // Guava 库的 Cache 实现缓存（本地缓存）
    @Resource
    private Cache<String, String> accessToken; // <appid, access_token>

    // Redis实现缓存（分布式缓存）
    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Resource
    private IWeixinApiService weixinApiService; // 微信开发平台api接口服务

    @Resource
    private IpLocationApiService ipLocationApiService; // ip地址解析api服务接口

    @Override
    public String createQrCodeTicket() throws IOException {
        // 1. 获取 access_token
        String accessToken = getAccessToken();

        // 2. 获取ticket
        WeixinQrCodeRequestDTO weixinQrCodeRequestDTO = WeixinQrCodeRequestDTO.builder()
                .action_name(WeixinQrCodeRequestDTO.ActionNameTypeVO.QR_SCENE.getCode())
                .action_info(WeixinQrCodeRequestDTO.ActionInfo.builder()
                        .scene(WeixinQrCodeRequestDTO.ActionInfo.Scene.builder()
                                .scene_id(100601)
                                .build())
                        .build())
                .expire_seconds(ticket_expire_time)
                .build();
        Call<WeixinQrCodeResponseDTO> call = weixinApiService.createQrCode(accessToken, weixinQrCodeRequestDTO);
        WeixinQrCodeResponseDTO weixinQrCodeResponseDTO = call.execute().body();
        // 断言 weixinQrCodeResponseDTO 不为 null
        assert weixinQrCodeResponseDTO != null;
        String ticket = weixinQrCodeResponseDTO.getTicket();
        return ticket;
    }

    @Override
    public void sendLoginTemplateMessage(String openid) throws IOException {
        // 1. 获取 accessToken 【实际业务场景，按需处理下异常】
        String accessToken = getAccessToken();

        // 2. 发送模板消息
        Map<String, Map<String, String>> data = new HashMap<>();
        // 2.1 添加用户信息
        WeixinTemplateMessageDTO.put(data, WeixinTemplateMessageDTO.TemplateKey.USER, openid);
        // 2.2 添加登录IP（通过RequestContextHolder获取HttpServlet，进而获得ip）
        String ip = IpLocationUtil.getLoginIp();
        WeixinTemplateMessageDTO.put(data, WeixinTemplateMessageDTO.TemplateKey.IP, ip);
        // 2.3 添加登录地区（省份 + 城市 + 运营商）
        String address = getLoginAddress();
        log.info("address:{}", address);
        WeixinTemplateMessageDTO.put(data, WeixinTemplateMessageDTO.TemplateKey.ADDRESS, address);

        WeixinTemplateMessageDTO templateMessageDTO = new WeixinTemplateMessageDTO(openid, template_id);
        templateMessageDTO.setUrl("https://gaga.plus");
        templateMessageDTO.setData(data);

        Call<Void> call = weixinApiService.sendMessage(accessToken, templateMessageDTO);
        call.execute();
    }

    /**
     * 获取微信开发平台access_token
     * */
    private String getAccessToken() throws IOException {
        // Guava 库的 Cache 实现 access_token 的本地缓存
//        String accessToken = this.accessToken.getIfPresent(appid);
//        if (null == accessToken) {
//            // access_token在 Cache 缓存中不存在
//            // 调用微信开发平台api接口服务，根据 grant_type 、 appid 和 app_secret 获得 access_token
//            Call<WeixinTokenResponseDTO> call = weixinApiService.getToken("client_credential", appid, appSecret);
//            WeixinTokenResponseDTO weixinTokenResponseDTO = call.execute().body();
//            // 断言 WeixinTokenResponseDTO 不为 null
//            assert weixinTokenResponseDTO != null;
//            accessToken = weixinTokenResponseDTO.getAccess_token();
//            // 将 access_token 缓存到 Cache 中
//            this.accessToken.put(appid, accessToken);
//        }
//        return accessToken;

        // Redis 实现 access_token 的分布式缓存
        String accessToken = redisTemplate.opsForValue().get(buildAccessTokenKey(appid));
        if (StringUtils.isBlank(accessToken)) {
            // access_token在 Cache 缓存中不存在
            // 调用微信开发平台api接口服务，根据 grant_type 、 appid 和 app_secret 获得 access_token
            Call<WeixinTokenResponseDTO> call = weixinApiService.getToken("client_credential", appid, appSecret);
            WeixinTokenResponseDTO weixinTokenResponseDTO = call.execute().body();
            // 断言 WeixinTokenResponseDTO 不为 null
            assert weixinTokenResponseDTO != null;
            accessToken = weixinTokenResponseDTO.getAccess_token();
            // 将 access_token 缓存到 Redis 中
            redisTemplate.opsForValue().set(buildAccessTokenKey(appid), accessToken, access_token_expires_time, TimeUnit.SECONDS);
        }
        return accessToken;
    }

    private String buildAccessTokenKey(String appid) {
        return Constants.REDIS_WEIXIN_PREFIX + Constants.RedisKeyEnum.ACCESS_TOKEN.getKeyPrefix() + appid;
    }

    /**
     * TODO: 暂时的IP解析服务
     * 根据IP地址解析地理位置（格式：省 市 运营商）
     */
    public String getLoginAddress() throws IOException {
        String ip = IpLocationUtil.getLoginIp();

        if (ip == null || StringUtils.isBlank(ip) || "127.0.0.1".equals(ip)) {
            return "本地网络";
        }

        Call<IpLocationResponseDTO> call = ipLocationApiService.getIpLocation(ip, "true");
        IpLocationResponseDTO ipLocationRes = call.execute().body();

        assert ipLocationRes != null;
        // 若没有错误，直接返回接口提供的完整地址
        if (StringUtils.isBlank(ipLocationRes.getError())) {
            return ipLocationRes.getAddress();
        }

        return "未知地点";
    }
}


